#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <sys/timerfd.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <termios.h>
#include "serial.h"
#include "packet.h"
#include <time.h>
#include "fifo.h"
#include "device_info.h"
#include "group_command.h"
#include "chu_switch.h"
#include "response.h"
#define MAX_EVENTS 10        // epoll 一次最多等待的事件数
#define TIMER_PERIOD_MS 2000 // 周期性定时器：2秒
// 全局变量，用于信号处理
// int timer_fd = -1;
int serial_fd = -1;
int internal_fifo_fd = -1;
int read_fx3_fifo = -1;
int write_fx3_fifo = -1;
bool send_idle = true;
volatile sig_atomic_t keep_running = 1;

chu_analg_rel_t chu_analg_rel;
chu_switch_t chu_switch;
ccu_switch_t ccu_switch;
// 函数声明
void signal_handler(int sig);

/**
 * @brief 信号处理函数
 */
void signal_handler(int sig)
{
    (void)sig; // 避免未使用参数警告
    keep_running = 0;
}
int epoll_add(int fd, int epoll_fd, uint32_t events)
{
    struct epoll_event event;
    // 5. 将串口 fd 添加到 epoll 监控 (监听可读事件)
    event.events = events; // 监听可读
    event.data.fd = fd;
    if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &event) == -1)
    {
        perror("epoll_ctl: serial_fd");
        close(fd);
        return -1;
    }
    return 0;
}
int start_timer(int fd, int ms, bool expired)
{
    // 设置定时器时间
    int sec = ms / 1000;
    int nsec = ms % 1000 * 1000 * 1000;
    struct itimerspec new_value = {};
    new_value.it_value.tv_sec = sec; // 第一次触发时间：1秒
    new_value.it_value.tv_nsec = nsec;
    if (expired)
    {
        new_value.it_interval.tv_sec = sec;
        new_value.it_interval.tv_nsec = nsec;
    }
    else
    {

        new_value.it_interval.tv_sec = 0; // it_interval=0 支持性一次
        new_value.it_interval.tv_nsec = 0;
    }

    if (timerfd_settime(fd, 0, &new_value, NULL) == -1)
    {
        perror("timerfd_settime");
        exit(EXIT_FAILURE);
        return -1;
    }
    return 0;
}
uint8_t calc_data_sum(uint8_t *data, int data_len)
{
    uint8_t totalsum = 0;
    for (int i = 0; i < data_len; i++)
    {

        totalsum += data[i];
    }

    return 256 - (totalsum % 256);
}
bool checksum_frame_ok(uint8_t *arr, int size)
{
    uint8_t tx_checksum = 0;
    uint8_t paclen = arr[1];
    uint8_t checksum = arr[paclen + 2];
    if (paclen + 3 > size)
        return false;
    for (int i = 0; i < paclen + 2; i++)
    {
        tx_checksum += arr[i];
    }
    tx_checksum = 0x100 - tx_checksum % 0x100;
    if (checksum == tx_checksum)
        return true;
    else
        return false;
}
bool check_frame_Integrity(uint8_t *data, int size)
{
    uint8_t paclen = data[1];
    if (paclen > 61)
    {
        return false;
    }
    if (paclen + 3 <= size)
    {
        if (checksum_frame_ok(data, paclen + 3))
            return true;
        else
        {
            output_data("checksum_frame error", data, size);
            return false;
        }
    }
    else
    {
        return false;
    }
}
extern bool send_command_flag;
extern bool start_timer_flags;
void build_data(uint8_t *dest, uint8_t *src, int n)
{
    for (int i = 0; i < n; i++)
    {
        dest[i] = src[i];
    }
}
int loop_read(int fd, uint8_t *data, int len)
{
    uint8_t temp = 0x00, i = 0, nread;
    uint8_t size = len;
    uint8_t *ptr = data;
    while (size > 0)
    {
        nread = read(fd, &temp, 1);
        if (nread > 0)
        {
            ptr[i] = temp;
            size--;
            i++;
        }
    }
    return i;
}
int handle_recv_message(int fd)
{
    int n = 0, pclen;
    uint8_t data[64] = {0};
    // 串口有数据可读
    n = loop_read(fd, data, 3);
    if (n == 3)
    {
        if (data[2] > 0x01 && data[2] != 0x90)
        {
            // tcflush(fd, TCIFLUSH);
            // send_nak(0x90, data[0]);
            pclen = data[1];
            if (pclen > 61)
            {
                tcflush(fd, TCIFLUSH);
                send_nak(data[2], data[0]);
            }
            n = loop_read(fd, data + 3, pclen);
            if (n == pclen)
            {
                if (check_frame_Integrity(data, pclen + 3))
                    sendack(data[2], data[0]);
            }
            else
            {
                output_data("recv header error:", data, 3 + n);
                tcflush(fd, TCIFLUSH);
                send_nak(data[2], data[0]);
            }
        }
        else
        {
            pclen = data[1]; // 可以添加长度的判断检测
            n = loop_read(fd, data + 3, pclen);
            if (n != pclen)
            {
                output_data("recv body error:", data, n + 3);
                tcflush(fd, TCIFLUSH);
                send_nak(data[2], data[0]);
            }
            else
            {
                if (check_frame_Integrity(data, pclen + 3))
                {
                    output_data("recv data ok:", data, pclen + 3);
                    parse_packet(fd, data, pclen + 3);
                }
                else
                {
                    output_data("recv data error:", data, pclen + 3);
                    tcflush(fd, TCIFLUSH);
                    send_nak(data[2], data[0]);
                }
            }
        }
    }
    else
    {
        printf("#######################n:%d\n", n);
        tcflush(fd, TCIFLUSH);
        send_nak(0x90, data[0]);
    }

    return 0;
}
int clear_time_flag(int fd)
{
    uint64_t expirations;
    int s = read(fd, &expirations, sizeof(expirations));
    if (s != sizeof(expirations))
    {
        perror("timerfd read");
        return -1;
    }
    return 0;
}
uint8_t toggle_value(uint8_t origin_value, uint8_t value)
{
    uint8_t result = origin_value;
    for (int i = 0; i < 8; i++)
    {
        if (CHECK_BIT(value, i))
        {
            TOGGLE_BIT(result, i);
        }
    }
    return result;
}
int reponse_rcp_switch_rel(uint8_t *data, int data_len)
{
    // 01 25 20 21 00 00 21 01 04 21 03 00 21 04 00 21 06 08 21 07 00 21 08 00 21 09 00 21 0a 00 21 0f 03 21 13 00 21 14 03 b6
    // /01 07 20 21 18 03 21 1d 03 5b
    // 01 22 20 21 40 00 21 81 39 21 82 21 21 83 c0 21 84 08 21 85 4d 21 86 00 21 87 03 21 8b 0c 21 8d 01 21 8e 00 51
    uint8_t buffer[64] = {0};
    uint8_t addr = 0, index = 0;
    buffer[0] = 0x01;
    buffer[2] = 0x20;
    uint8_t per = 3;
    uint8_t type = CHU_SWITCH_ABS;
    uint8_t value;
    for (int i = 0; i < data_len; i += per)
    {
        addr = data[i + 1];
        value = data[i + 2];
        switch (addr)
        {
        case 0x00:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = chu_switch.shutter_select;
            index++;
            break;
        case 0x01:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = chu_switch.master_gain_select;
            index++;
            break;
        case 0x03:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x00;
            index++;
            break;
        case 0x04:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x00;
            index++;
            break;
        case 0x06:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x08;
            index++;
            break;
        case 0x07:
        case 0x08:
        case 0x09:
        case 0x0a:
        case 0x13:
        case 0x40:
        case 0x8e:
        case 0x8f:
        case 0x93:
        case 0xa0:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x00;
            index++;
            break;

        case 0x0f:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x03;
            index++;
            break;
        case 0x14:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x03;
            index++;
            break;
        case 0x18:
        case 0x1d:
        case 0x87:
        case 0xa4:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x03;
            index++;
            break;
        case 0x81:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = value ? toggle_value(chu_switch.switch_addr81, value) : chu_switch.switch_addr81;
            chu_switch.switch_addr81 = buffer[index * per + 5];
            index++;
            break;
        case 0x82:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x21;
            index++;
            break;
        case 0x83:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = value ? toggle_value(chu_switch.switch_addr83, value) : chu_switch.switch_addr83;
            chu_switch.switch_addr83 = buffer[index * per + 5];
            index++;
            break;
        case 0x84:
        case 0xa2:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x08;
            index++;
            break;
        case 0x85:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x4d;
            index++;
            break;
        case 0x86:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = value ? toggle_value(chu_switch.switch_addr86, value) : chu_switch.switch_addr86;
            chu_switch.switch_addr86 = buffer[index * per + 5];
            index++;
            break;
        case 0x8b:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x0c;
            index++;
            break;
        case 0x8d:
        case 0x91:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = 0x01;
            index++;
            break;

        default:
            break;
        }
    }
    if (index > 0)
    {
        uint8_t pclen = index * per + 1;
        buffer[1] = pclen; // 1:校验位
        buffer[index * per + 3] = calc_data_sum(buffer, index * per + 3);
        // 数据长度  data:(data_len+1)* per  + (1 校验位)
        write(serial_fd, buffer, index * per + 3);
        // output_data("camera response:", buffer, pclen + 3);
    }
}
uint16_t bytes2short(uint8_t high_data_bit, uint8_t low_data_bit)
{
    uint16_t value = ((uint16_t)(high_data_bit << 8) + low_data_bit);
    return value;
}
int short2bytes(int16_t current, uint8_t *high_data_bit, uint8_t *low_data_bit)
{
    uint8_t bytes = 0;
    current = current & 0x7fff;
    bytes = current >> 8;
    *high_data_bit = bytes;
    bytes = (uint8_t)(current & 0xff);
    *low_data_bit = bytes;
    return 0;
}
int fill3bytes(uint8_t type, uint8_t addr, uint8_t value)
{

    return 0;
}
int fill4bytes(uint8_t *data, uint8_t offset, uint8_t type, uint8_t addr, uint16_t value)
{
    uint8_t high_data_bit = 0x00, low_data_bit = 0x00;
    if (offset > 59)
        return -1;
    data[offset] = type;
    data[offset + 1] = addr;
    short2bytes(value, &high_data_bit, &low_data_bit);
    data[offset + 2] = high_data_bit;
    data[offset + 3] = low_data_bit;

    return 0;
}
int reponse_rcp_analog_rel(uint8_t *data, int data_len)
{
    /*01 35 20
    23 01 eb f6
    23 03 08 91
    23 04 00 00
    23 05 00 00
    23 06 00 00
    23 07 00 00
    23 08 00 00
    23 09 00 00
    23 0a 00 00
    23 0b 00 00
    23 0c 00 00
    23 0d 00 00
    23 0e 00 00
    02

   */

    /*
    01 21 20
    23 10 f7 80
    23 11 00 00
    23 12 00 00
    23 13 00 00
    23 14 00 00
    23 18 00 00
    23 1c 00 00
    23 1d 00 00 84
    */

    /*

    01 0d 20
    23 40 00 00
    23 41 01 b1
    23 43 00 00
    f3
    */
    /*

    01 1d 20
    23 44 1d 27
    23 50 00 00
    23 54 00 00
    23 55 1d 27
    23 56 00 00
    23 57 1d 27
    23 60 34 fc
    87
    */

    /*
    544 Cam Tx: 01 1d 20
    23 86 00 00
    23 87 00 00
    23 88 de ff
    23 89 a0 92
    23 8a 40 02
    23 8b e1 70
    23 8c 53 30
    e9


    */

    /*

    01 39 20
    23 8d ff 02
    23 8e 90 de
    23 8f 00 00
    23 90 00 00
    23 91 00 a3
    23 92 00 00
    23 93 00 00
    23 94 09 12
    23 95 00 00
    23 96 10 02
    23 97 00 75
    23 98 02 b0
    23 99 03 16
    23 9a 7f ff
    ae

    */

    /*
    552 Cam Tx: 01 35 20
    23 9b 31 9a
    23 9c 00 00
    23 9e 00 00
    23 9f ff 00
    23 a0 00 00
    23 a1 00 00
    23 a2 ff c6
    23 a3 00 00
    23 a4 00 00
    23 a5 00 00
    23 a6 00 00
    23 a7 00 00
    23 a8 00 00
    1c
*/
    /*

    556 Cam Tx: 01 29 20
    23 a9 ed 02
    23 aa 3e fe
    23 ac e5 80
    23 ae 00 00
    23 af 00 00
    23 b0 00 00
    23 b3 00 8a
    23 b4 00 00
    23 b5 e1 dc
    23 b7 00 00
    a2

    */

    /*
    01 19 20
    23 c4 00 00
    23 c6 fe 00
    23 c7 ff 02
    23 c8 00 00
    23 c9 00 21
    23 ca 00 22
    06
    */
    uint8_t buffer[64] = {0};
    uint8_t high_byte = 0, low_byte = 0, index = 0, addr = 0x00;
    uint8_t per = 4, type = CHU_ANALOG_ABS;
    uint16_t increment = 0x00;
    buffer[0] = 0x01;
    buffer[2] = 0x20;
    for (int i = 0; i < data_len; i += per)
    {
        addr = data[i + 1];
        high_byte = data[i + 2];
        low_byte = data[i + 3];
        increment = bytes2short(high_byte, low_byte);
        switch (addr)
        {
        case 0x01:
            increment = (increment == 0) ? 0xebf6 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x03:
            increment = (increment == 0) ? 0x0891 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x10:
            increment = (increment == 0) ? 0xf780 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x04:
        case 0x05:
        case 0x06:
        case 0x07:
        case 0x08:
        case 0x09:
        case 0x0a:
        case 0x0b:
        case 0x0c:
        case 0x0d:
        case 0x0e:
        case 0x11:
        case 0x12:
        case 0x13:
        case 0x14:
        case 0x18:
        case 0x1c:
        case 0x1d:
        case 0x1e:
        case 0x1f:
        case 0x20:
        case 0x40:
        case 0x43:
        case 0x50:
        case 0x54:
        case 0x56:
        case 0x86:
        case 0x87:
        case 0x8f:
        case 0x90:
        case 0x92:
        case 0x93:
        case 0x95:
        case 0x9c:
        case 0x9e:
        case 0xa0:
        case 0xa1:
        case 0xa3:
        case 0xa4:
        case 0xa5:
        case 0xa6:
        case 0xa7:
        case 0xa8:
        case 0xae:
        case 0xaf:
        case 0xb0:
        case 0xb4:
        case 0xb7:
        case 0xc4:
        case 0xc8:
            increment = (increment == 0) ? 0x00 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x41:
            increment = (increment == 0) ? 0x01b1 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x44:
        case 0x55:
        case 0x57:
            increment = (increment == 0) ? 0x1d27 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x60:
            chu_analg_rel.iris = (increment == 0) ? chu_analg_rel.iris : chu_analg_rel.iris + increment;
            chu_analg_rel.iris = chu_analg_rel.iris & 0x7fff;
            fill4bytes(buffer, index * per + 3, type, addr, chu_analg_rel.iris);
            index++;
            break;
        case 0x88:
            increment = (increment == 0) ? 0xdeff : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x89:
            increment = (increment == 0) ? 0xa092 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x8a:
            increment = (increment == 0) ? 0x4002 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x8b:
            increment = (increment == 0) ? 0xe170 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x8c:
            increment = (increment == 0) ? 0x5330 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x8d:
            increment = (increment == 0) ? 0xff02 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x8e:
            increment = (increment == 0) ? 0x90de : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x91:
            increment = (increment == 0) ? 0x00a3 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x94:
            increment = (increment == 0) ? 0x0912 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x96:
            increment = (increment == 0) ? 0x1002 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x97:
            increment = (increment == 0) ? 0x0075 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x98:
            increment = (increment == 0) ? 0x02b0 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x99:
            increment = (increment == 0) ? 0x0316 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x9a:
            increment = (increment == 0) ? 0x7fff : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x9b:
            increment = (increment == 0) ? 0x319a : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0x9f:
            increment = (increment == 0) ? 0xff00 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xa2:
            increment = (increment == 0) ? 0xffc6 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xa9:
            chu_analg_rel.master_black = (increment == 0) ? chu_analg_rel.master_black : increment + chu_analg_rel.master_black;
            chu_analg_rel.master_black = chu_analg_rel.master_black & 0x7fff;
            fill4bytes(buffer, index * per + 3, type, addr, chu_analg_rel.master_black);
            index++;
            break;
        case 0xaa:
            increment = (increment == 0) ? 0x3efe : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xac:
            increment = (increment == 0) ? 0xe580 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xb3:
            increment = (increment == 0) ? 0x008a : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xb5:
            increment = (increment == 0) ? 0xe1dc : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xc6:
            increment = (increment == 0) ? 0xfe00 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xc7:
            increment = (increment == 0) ? 0xff02 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xc9:
            increment = (increment == 0) ? 0x0021 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        case 0xca:
            increment = (increment == 0) ? 0x0022 : increment;
            fill4bytes(buffer, index * per + 3, type, addr, increment);
            index++;
            break;
        default:
            break;
        }
    }
    if (index > 0)
    {
        uint8_t pclen = index * per + 1;
        buffer[1] = pclen; // 1:校验位
        buffer[index * per + 3] = calc_data_sum(buffer, index * per + 3);
        // 数据长度  data:(data_len+1)* per  + (1 校验位)
        write(serial_fd, buffer, index * per + 3);

        //  output_data("========>camera response:", buffer, pclen + 3);
    }

    return 0;
}
int response_rcp_ext_analog_rel(uint8_t *data, int data_len)
{
    uint8_t buffer[64] = {0};
    uint8_t checksum = 0, index = 0;
    buffer[0] = 0x01;
    buffer[2] = 0x20;
    uint8_t per = 4;
    /*
    01 09 20
    3d 00 00 22
    3d 10 00 00
    2a
    */
    uint8_t type = CHU_EXT_ANALOG_ABS;

    for (int i = 0; i < data_len; i++)
    {

        switch (data[i])
        {
        case 0x00:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = data[i];
            buffer[index * per + 5] = 0x00;
            buffer[index * per + 6] = 0x22;
            index++;
            break;

        case 0x10:
            buffer[index * per + 3] = type;
            buffer[index * per + 4] = data[i];
            buffer[index * per + 5] = 0x00;
            buffer[index * per + 6] = 0x00;
            index++;
            break;

        default:
            break;
        }
    }
    if (index > 0)
    {
        uint8_t pclen = index * per + 1;
        buffer[1] = pclen; // 1:校验位
        buffer[index * per + 3] = calc_data_sum(buffer, index * per + 3);
        // 数据长度  data:(data_len+1)* per  + (1 校验位)
        write(serial_fd, buffer, index * per + 3);
    }

    return 0;
}
int reponse_rcp_analog_abs(uint8_t *data, int data_len)
{

    uint8_t buffer[64] = {0};
    uint8_t high_byte = 0, low_byte = 0, index = 0, addr = 0x00;
    uint8_t per = 4, type = CHU_ANALOG_ABS;
    uint16_t increment = 0x00;
    buffer[0] = 0x01;
    buffer[2] = 0x20;
    for (int i = 0; i < data_len; i += per)
    {
        addr = data[i + 1];
        increment = bytes2short(high_byte, low_byte);
        switch (addr)
        {
        case 0xa9:
            chu_analg_rel.master_black = (increment == 0) ? chu_analg_rel.master_black : increment;
            chu_analg_rel.master_black = chu_analg_rel.master_black & 0x7fff;
            fill4bytes(buffer, index * per + 3, type, addr, chu_analg_rel.master_black);
            index++;
            break;
        default:
            break;
        }
    }
    if (index > 0)
    {
        uint8_t pclen = index * per + 1;
        buffer[1] = pclen; // 1:校验位
        buffer[index * per + 3] = calc_data_sum(buffer, index * per + 3);
        // 数据长度  data:(data_len+1)* per  + (1 校验位)
        write(serial_fd, buffer, index * per + 3);
    }
    return 0;
}
int response_auto_setup()
{

    uint8_t buffer[64] = {0x04, 0x05, 0x20, 0x26, 0x00, 0x00, 0x00, 0xb1};
    write(serial_fd, buffer, buffer[1] + 3);
    return 0;
}
int response_who_q(uint8_t *data, int data_len)
{
    uint8_t buffer[64] = {0};
    uint pclen = 0x02;
    buffer[0] = data[0];
    buffer[1] = pclen;
    buffer[2] = data[1];
    buffer[3] = WHO_ARE_YOU;
    buffer[4] = calc_data_sum(buffer, 4);

    write(serial_fd, buffer, buffer[1] + 3);
    output_data("========>response_who_q:", buffer, pclen + 3);
    return 0;
}
int response_auto_setup_info()
{
    //
    uint8_t buffer[64] = {0x01, 0x17, 0x20, 0x26, 0x00, 0x00, 0x00, 0x27, 0x05, 0x03, 0x00, 0x27, 0x07, 0x07, 0x01, 0x27, 0x0b, 0x07, 0x05, 0x28, 0x05, 0x03, 0x07, 0x00, 0x10, 0xb8};
    uint8_t pclen = buffer[1];
    write(serial_fd, buffer, pclen + 3);
    output_data("========>response_auto_setup_info:", buffer, pclen + 3);
    return 0;
}
int response_infornation()
{
    uint8_t buffer[64] = {0x90, 0x1f, 0x20, 0x10, 0x01, 0x1b, 0x01, 0x05, 0x42, 0x02, 0x02, 0x11, 0x03, 0x00, 0x08, 0x07, 0x00, 0x01, 0x08, 0x00, 0x00, 0x80, 0x30, 0x0d, 0x81, 0x00, 0x00, 0x82, 0x00, 0x00, 0x83, 0x00, 0x00, 0x4a};

    uint8_t pclen = buffer[1];
    write(serial_fd, buffer, pclen + 3);
    output_data("========>response_infornation:", buffer, pclen + 3);
    return 0;
}
#if 0
extern int init_send;
int auto_response()
{
    switch (init_send)
    {
    case 3:
        report1_message();
        send_idle = false;
        init_send--;
        break;
    case 2:
        report2_message();
        send_idle = false;
        init_send--;
        break;
    case 1:
        report3_message();
        send_idle = false;
        init_send--;
        break;
    default:
        break;
    }

    return 0;
}
#endif
int update_shutter_value(uint8_t max, uint8_t min, uint8_t add)
{
    if (add == 0x01)
    {
        if (chu_switch.shutter_select > min)
        {
            chu_switch.shutter_select--;
        }
        else
        {
            chu_switch.shutter_select = min;
        }
    }
    else
    {
        if (chu_switch.shutter_select < max)
            chu_switch.shutter_select++;
        else
            chu_switch.shutter_select = max;
    }
    return 0;
}
int handle_shutter_switch(uint8_t value)
{
    uint8_t type = value >> 6;
    uint8_t origin = chu_switch.shutter_select;
    switch (type)
    {
    case 0x00:
        break;
    case 0x01: // Down
        update_shutter_value(0x06, 0x00, 0x01);
        break;
    case 0x02: // Up
        update_shutter_value(0x06, 0x00, 0x10);
        break;
    case 0x03:
        break;
    default:
        break;
    }
    printf(".....................type:%d origin:%d shutter_select:%d \n\r", type, origin, chu_switch.shutter_select);

    return 0;
}
int update_gain_value(uint8_t max, uint8_t min, uint8_t value)
{
    if (value == 0x01)
    {
        if (chu_switch.master_gain_select > min)
            chu_switch.master_gain_select--;
        else
            chu_switch.master_gain_select = min;
    }
    else
    {
        if (chu_switch.master_gain_select < max)
            chu_switch.master_gain_select++;
        else
            chu_switch.master_gain_select = max;
    }

    return 0;
}
int handle_master_gain_switch(int value)
{
    uint8_t type = value >> 6;
    switch (type)
    {
    case 0x00:
        break;
    case 0x01: // Down
        update_gain_value(0x12, 0x00, 0x01);
        break;
    case 0x02: // Up
        update_gain_value(0x12, 0x00, 0x10);
        break;
    case 0x03:
    default:
        break;
    }

    return 0;
}
int response_switch2rcp(uint8_t type, uint8_t addr, uint8_t value)
{
    // 01 04 20 21 00 06 b4
    uint8_t nwrite = 0;
    uint8_t buffer[64] = {0};
    buffer[0] = 0x01;
    buffer[1] = 0x04;
    buffer[2] = 0x20;
    buffer[3] = type;
    buffer[4] = addr;
    buffer[5] = value;
    buffer[6] = calc_data_sum(buffer, 6);
    uint8_t pclen = buffer[1];
    nwrite = write(serial_fd, buffer, pclen + 3);
    output_data("========>response_switch2rcp:", buffer, pclen + 3);
    return nwrite;
}
int response_switch_abs(uint8_t *data, int data_len)
{

    uint8_t per = 3;
    uint8_t addr = 0x00;
    for (int i = 0; i < data_len; i += per)
    {
        addr = data[i + 1];
        switch (addr)
        {
        case 0x00:
            handle_shutter_switch(data[i + 2]);
            response_switch2rcp(CHU_SWITCH_ABS, addr, chu_switch.shutter_select);
            break;
        case 0x01:
            handle_master_gain_switch(data[i + 2]);
            response_switch2rcp(CHU_SWITCH_ABS, addr, chu_switch.master_gain_select);
            break;
        }
    }
}
int response_i_am_here(uint8_t *data, int data_len)
{
    uint8_t buffer[64] = {0};
    uint pclen = 0x02;
    buffer[0] = data[0];
    buffer[1] = pclen;
    buffer[2] = data[1];
    buffer[3] = I_AM_HERE;
    buffer[4] = calc_data_sum(buffer, 4);

    write(serial_fd, buffer, pclen + 3);
    output_data("========>response_i_am_here:", buffer, pclen + 3);
    return 0;
}
/*
17441 Cam Tx: 01 05 20 23 a9 33 d0 0b

17441 Rcp Tx: 02 05 90 22 a9 00 10 8e

11110 Rcp Tx: 02 04 90 20 86 80 44
11112 Cam Tx: 01 04 20 21 86 80 b4
*/
int response_ccu_switch_rel(uint8_t *data, uint8_t data_len)
{
    uint8_t per = 3, pclen = 0;
    uint8_t addr = 0x00, index = 0, type;
    uint8_t buffer[64] = {0};
    buffer[0] = 0x01;
    buffer[2] = 0x20;

    for (int i = 0; i < data_len; i += per)
    {
        type = data[i];
        addr = data[i + 1];
        switch (addr)
        {
        case 0x10:
            buffer[3] = type + 1;
            buffer[index * per + 4] = addr;
            buffer[index * per + 5] = data[i + 2] ? toggle_value(ccu_switch.ccu_switch_addr10, data[i + 2]) : ccu_switch.ccu_switch_addr10;
            ccu_switch.ccu_switch_addr10 = buffer[index * per + 5];
            index++;
            break;
        case 0x01:
            break;
        default:
            break;
        }
    }
    if (index > 0)
    {
        uint8_t pclen = index * per + 1;
        buffer[1] = pclen; // 1:校验位
        buffer[index * per + 3] = calc_data_sum(buffer, index * per + 3);
        // 数据长度  data:(data_len+1)* per  + (1 校验位)
        write(serial_fd, buffer, index * per + 3);
    }
    return 0;
}
int timer_handle_rcp_requst(int fd)
{
    uint8_t data[64] = {0};
    ssize_t nread = read(fd, data, sizeof(data) - 1);
    output_data("read fifo data:", data, nread);
    switch (data[0])
    {
    case ACK:
        //  auto_response();
        break;
    case INFORMATION:
        response_infornation();
        break;
    case WHO_ARE_YOU:
        response_who_q(data + 1, nread - 1);
        break;
    case I_AM_HERE:
        response_i_am_here(data + 1, nread - 1);
        break;
    case CHU_SWITCH_REL:
        reponse_rcp_switch_rel(data, nread);
        break;
    case CHU_SWITCH_ABS:
        response_switch_abs(data, nread);
        break;
    case CHU_ANALOG_REL:
        reponse_rcp_analog_rel(data, nread);
        break;
    case CHU_ANALOG_ABS:
        reponse_rcp_analog_abs(data, nread);
        break;
    case CHU_EXT_ANALOG_REL:
        response_rcp_ext_analog_rel(data + 1, nread - 1);
        break;
    case CHU_AUTO_SETUP_CONTROL:
        response_auto_setup();
        break;
    case CHU_AUTO_SETUP_INFORMATION:
        response_auto_setup_info();
        break;
    case CCU_SWITCH_REL:
        response_ccu_switch_rel(data, nread);
        break;
    default:
        break;
    }
    delay_ms(5);
    return 0;
}
int device_param_init()
{
    chu_switch.shutter_select = 0x00;
    chu_switch.master_gain_select = 0x0e;
    chu_switch.switch_addr81 = 0xb8;
    chu_switch.switch_addr83 = 0xc0;
    chu_switch.switch_addr86 = 0x00;
    chu_analg_rel.iris = 0x34fc;
    chu_analg_rel.master_black = 0xef02;
    ccu_switch.ccu_switch_addr10 = 0x00;

    return 0;
}
// 02 05 90 22 60 00 70 77
int handle_recv_cam_data(int fd)
{
    uint8_t data[64];
    uint8_t nread;
    nread = read(fd, data, sizeof(data));
    if (nread < 0)
    {
        return -1;
    }
    else
    {
        output_data("read camera data:", data, nread);
    }
    return 0;
}
int main()
{
    int epoll_fd = -1;
    int nfds, n, ret;
    struct epoll_event events[MAX_EVENTS];
    // 1. 设置信号处理，捕获 Ctrl+C
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    device_param_init();
    read_fx3_fifo = open_fifo(CAM2RCP_FIFO);
    if (read_fx3_fifo < 0)
    {
        printf("open filename :%s", CAM2RCP_FIFO);
        goto end;
    }
    write_fx3_fifo = open_fifo(RCP2CAM_FIFO);
    if (write_fx3_fifo < 0)
    {
        printf("open filename :%s", RCP2CAM_FIFO);
        goto end;
    }
    internal_fifo_fd = open_fifo(FIFO_PATH);
    if (internal_fifo_fd < 0)
    {
        printf("open filename :%s", FIFO_PATH);
        goto end;
    }
    serial_fd = serial_init(SERIAL_PORT);
    if (serial_fd < 0)
    {
        fprintf(stderr, "Error opening %s: %s\n", SERIAL_PORT, strerror(errno));
        goto end;
    }
#if 0
    looptime_fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK | TFD_CLOEXEC);
    if (looptime_fd == -1)
    {
        perror("timerfd_create");
        goto end;
    }
#endif
    // 4. 创建 epoll 实例
    epoll_fd = epoll_create1(0);
    if (epoll_fd == -1)
    {
        perror("epoll_create1");
        goto end;
    }
    ret = epoll_add(serial_fd, epoll_fd, EPOLLIN);
    if (ret < 0)
    {
        perror("epoll_add");
        goto end;
    }
    ret = epoll_add(read_fx3_fifo, epoll_fd, EPOLLIN);
    if (ret < 0)
    {
        perror("epoll_add");
        goto end;
    }
#if 0
    ret = epoll_add(looptime_fd, epoll_fd, EPOLLIN);
    if (ret < 0)
    {
        perror("epoll_add");
        goto end;
    }
#endif
    ret = epoll_add(internal_fifo_fd, epoll_fd, EPOLLIN);
    if (ret < 0)
    {
        perror("epoll_add");
        goto end;
    }
    // 7. 主事件循环
    while (keep_running)
    {
        // 等待事件发生，-1 表示无限等待
        nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, 500);
        if (nfds == -1)
        {
            if (errno == EINTR)
            {
                // 被信号中断，检查 keep_running 并继续或退出
                if (!keep_running)
                    break;
                continue;
            }
            else
            {
                perror("epoll_wait");
                break;
            }
        }
        else if (nfds == 0)
        {
            printf("....................timout\n");
        }

        // 处理所有就绪的事件
        for (int i = 0; i < nfds; ++i)
        {
            if (events[i].data.fd == serial_fd)
            {
                handle_recv_message(serial_fd);
            }
            else if (internal_fifo_fd == events[i].data.fd)
            {
                timer_handle_rcp_requst(internal_fifo_fd);
            }
            else if (read_fx3_fifo == events[i].data.fd)
            {
                handle_recv_cam_data(read_fx3_fifo);
            }
#if 0
            else if (looptime_fd == events[i].data.fd)
            {
                clear_time_flag(looptime_fd);
            }
#endif

        } // end for

    } // end while

// 8. 清理资源
end:
    printf("Cleaning up...\n");
    if (epoll_fd != -1)
    {
        close(epoll_fd);
    }
    if (read_fx3_fifo != -1)
    {
        close(read_fx3_fifo);
    }
    if (write_fx3_fifo != -1)
    {
        close(write_fx3_fifo);
    }
    if (internal_fifo_fd != -1)
    {
        close(internal_fifo_fd);
    }

    if (serial_fd != -1)
    {
        close(serial_fd);
    }
    printf("Program exited.\n");

    return EXIT_SUCCESS;
}
